package controllers;

import static play.data.Form.form;
import interceptors.AuthCheckInterceptor;
import interceptors.DefaultInterceptor;
import interceptors.UserSessionInterceptor;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;

import models.User;
import collectors.calendar.models.Event;
import collectors.email.models.GmailEmail;
import collectors.file.models.FileInfo;
import collectors.people.models.PeopleUser.FacebookData;
import play.data.DynamicForm;
import play.libs.Akka;
import play.libs.F;
import play.libs.F.Function;
import play.libs.F.Promise;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.With;
import services.CollectorService;
import services.UserService;
import util.UserSession;
import exceptions.NoUUIDException;

@With({DefaultInterceptor.class, UserSessionInterceptor.class, AuthCheckInterceptor.class})
public class Search extends Controller{
	
	private static final UserService userService = UserService.getInstance();

	public static Result index() {
		try {
			UserSession userSession = userService.getUserSession(session());
			return ok(views.html.search.render(userSession));
		} catch (NoUUIDException e) {
			e.printStackTrace();
			return unauthorized();
		}
    }
	
	public static Result search(){
		try {
			final UserSession userSession = userService.getUserSession(session());
//			String filyou = Play.application().configuration().getString("sm.filyou.url");
			DynamicForm dynamicForm = form().bindFromRequest();
			final String query = dynamicForm.get("q");
			
			User user = userSession.getUser();
			Promise<List<Event>> eventsPromise;
			Promise<List<FileInfo>> filesPromise;
			Promise<List<GmailEmail>> emailsPromise;
			Promise<List<FacebookData>> peoplePromise;

			if (userSession.getUser().filyouLinked) {
				filesPromise = CollectorService.searchFiles(
						user.filyouId, query, null);
			} else {
				filesPromise = genEmptyPromise(FileInfo.class);
			}
			if (user.calendaryouLinked) {
				eventsPromise = CollectorService.searchEvents(
						user.calendaryouId, query);
			} else {
				eventsPromise = genEmptyPromise(Event.class);
			}
			if (user.peopleyouLinked) {
				peoplePromise = CollectorService.searchPeople(
						user.peopleyouId, query);
			} else {
				peoplePromise = genEmptyPromise(FacebookData.class);
			}
			if (user.emaiyouLinked) {
				emailsPromise = CollectorService.searchEmails(user.emaiyouId,query,10);
			} else {
				emailsPromise = genEmptyPromise(GmailEmail.class);
			}

			//FIXME I have no idea how to do this in a typesafe manner
			return async(Promise.sequence(filesPromise, eventsPromise, peoplePromise, emailsPromise).map(
					new Function<List<List<? extends Object>>, Result>() {
						@Override
						public Result apply(List<List<? extends Object>> arg0)
								throws Throwable {
							List<FileInfo> files = (List<FileInfo>) arg0.get(0);
							List<Event> events = (List<Event>) arg0.get(1);
							List<FacebookData> people = (List<FacebookData>) arg0.get(2);
							List<GmailEmail> emails = (List<GmailEmail>) arg0.get(3);
							return ok (views.html.filyouresults.render(userSession, query, files, events, emails, people));
						}
					})); 
			
		} catch (NoUUIDException e) {
			e.printStackTrace();
			return unauthorized();
		}
	}
	
	private static <T> Promise<List<T>> genEmptyPromise(Class<T> type) {
		return Akka.future(new Callable<List<T>>() {
			@Override
			public List<T> call() throws Exception {
				return Collections.emptyList();
			}
		});
	}
}
